package com.easylinkin.linkappapi.openapi.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.common.utils.CommonUtils;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import com.easylinkin.linkappapi.elasticsearch.entity.EsResponsemodel;
import com.easylinkin.linkappapi.elasticsearch.util.EsCalendar;
import org.apache.commons.lang3.ObjectUtils;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.device.service.DeviceService;
import com.easylinkin.linkappapi.deviceattribute.entity.DeviceAttribute;
import com.easylinkin.linkappapi.deviceattribute.service.DeviceAttributeService;
import com.easylinkin.linkappapi.deviceattributestatus.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.deviceunit.entity.DeviceUnit;
import com.easylinkin.linkappapi.deviceunit.service.DeviceUnitService;
import com.easylinkin.linkappapi.elasticsearch.service.IEService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.tenant.entity.LinkappTenant;
import com.easylinkin.linkappapi.tenant.sevice.LinkappTenantService;
import org.springframework.util.StringUtils;

@Service
public class OpenApiDataVService {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(OpenApiDataVService.class);
    private static final int  HOURSTART  = 11;
    private static final int  HOUREND  = 13;
	
	@Resource
    LinkappUserContextProducer linkappUserContextProducer;
    @Resource
    IEService realService;
    @Resource
    LinkappTenantService linkappTenantService;

    @Resource
    private DeviceAttributeService deviceAttributeService;
    @Resource
    private DeviceService deviceService;
    
    @Resource
    private DeviceUnitService deviceUnitService;
    @Resource
    private DeviceAttributeStatusService deviceAttributeStatusService;

/*
	
	public IPage<Map> getHistoricDataFromEs(RequestModel<DeviceAttributeStatus> requestModel) {
        DeviceAttributeStatus queryModel = requestModel.getCustomQueryParams();
        Page page = requestModel.getPage();
        Assert.notNull(queryModel, "customQueryParams 不能为空");
        Assert.notNull(page, "page 不能为空");
        EsResponsemodel esResponsemodel = new EsResponsemodel();
        IPage<DeviceAttributeStatus> result = null;
        Long indexLong = page.getCurrent();
        Long sizeLong = page.getSize();
        Long beginTime = null;
        if (StringUtils.isNotEmpty(queryModel.getQueryTimeStart())) {
            beginTime = DateUtil.getDateFromYYYYMMDDHHmmss(queryModel.getQueryTimeStart()).getTime();
        }
        Long endTime = null;
        if (StringUtils.isNotEmpty(queryModel.getQueryTimeEnd())) {
            endTime = DateUtil.getDateFromYYYYMMDDHHmmss(queryModel.getQueryTimeEnd()).getTime();
        }

        LinkappTenant currentTenant = linkappTenantService.currentTenant();
        Assert.notNull(currentTenant, "当前租户为空");
        Assert.notNull(currentTenant.getProjectId(), "当前租户项目id为空");

        Long projectId = CommonUtils.parseLong(currentTenant.getProjectId());

        SearchHits searchHits = realService.getDeviceDataListFromES(queryModel.getDeviceCode(),queryModel.getPropCode(), projectId, indexLong.intValue(), sizeLong.intValue(), beginTime, endTime);
        if (searchHits == null) {
            return page;
        }
        LOGGER.info("es查询结果到设备历史数据条数 ：" + searchHits.getTotalHits());
        SearchHit[] results = searchHits.getHits();

        List<Map<String, Object>> records = new ArrayList<>();
        for (SearchHit hit : results) {
        	Map<String, Object> recordMap = new HashMap<String, Object>();
            Map<String, Object> sourceMap = hit.getSourceAsMap();
            for (Entry<String, Object> item : sourceMap.entrySet()) {//                如果是时间戳的long 类型 返回 时间格式
                try {
//                    1.590406860678E12 原时间
                	if(item.getKey().equalsIgnoreCase(queryModel.getPropCode())) {
                		recordMap.put(item.getKey(), item.getValue());
                	}
                    if (item.getKey().toLowerCase().contains("time")) {
                        Double doubleTimeValue = Double.parseDouble(String.valueOf(item.getValue()));
                        if (String.valueOf(doubleTimeValue.longValue()).length() == 13) {
                        	recordMap.put(item.getKey(), DateUtil.getYYYYMMDDHHMMSSDate(new Date(doubleTimeValue.longValue())));
                        }
                    }
                } catch (Exception e) {
                    LOGGER.info("时间转换有异常：{}", e.getMessage());
                }
            }
            if(sourceMap.get(queryModel.getPropCode()) == null) {
            	recordMap.put(queryModel.getPropCode(), "0");
            }
            records.add(recordMap);
        }

        setSpecsForEsRecords(queryModel, records);

        page.setRecords(records);
        page.setTotal(searchHits.getTotalHits());

        return page;
    }*/
	
    /**
     * 给es 查询结果塞入单位
     */
    public void setSpecsForEsRecords(DeviceAttributeStatus queryModel, List<Map<String, Object>> records) {
        if (ObjectUtils.isEmpty(queryModel.getDeviceUnitCode())&&ObjectUtils.isEmpty(queryModel.getVersion())) {
            return;
        }
        
        QueryWrapper deviceUnitqw = new QueryWrapper();
        deviceUnitqw.eq("code", queryModel.getDeviceUnitCode());
        deviceUnitqw.eq("version", queryModel.getVersion());
        List<DeviceUnit> deviceUnits = deviceUnitService.list(deviceUnitqw);
        if(!deviceUnits.isEmpty()) {
        	QueryWrapper qw = new QueryWrapper();
            qw.eq("device_unit_id", deviceUnits.get(0).getId());
            qw.eq("identifier", queryModel.getPropCode());
            qw.select("identifier", "specs");
            List<DeviceAttribute> deviceAttributes = deviceAttributeService.list(qw);
            if (ObjectUtils.isEmpty(deviceAttributes)) {
                return;
            }
            Map<String, String> deviceAttrMap = deviceAttributes.stream().collect(Collectors.toMap(DeviceAttribute::getIdentifier, DeviceAttribute::getSpecs));
            for (int i = 0; i < records.size(); i++) {
                Map<String, Object> record = records.get(i);
                record.put("specsMap", deviceAttrMap);
            }
        }
        
        
        

    }

    /**
     * 查询当天分时数据
     * @param deviceAttributeStatus
     * @return
     */
    public List<Map<String, Object>> getHistoricDataCurrDay(DeviceAttributeStatus deviceAttributeStatus) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> recordMap = new HashMap<>();
        //当天凌晨时间
        String gteString = EsCalendar.getStartTimeOfDay(0);
        //当前时间
        String lteString = EsCalendar.getCurerntTime();
        //projectId
        LinkappTenant currentTenant = linkappTenantService.currentTenant();
        String projectId = currentTenant.getProjectId();
        SearchHits searchHits = realService.getHistoricDataCurrDay(projectId, deviceAttributeStatus.getDeviceCode(), gteString, lteString, deviceAttributeStatus.getPropName());
        List<Map<String, Object>> mapList2 = realService.parseResultFromSearchHit(searchHits.getHits());
        for (Map<String, Object> sourceMap : mapList2) {
            //2020-08-22T00:04:00.973+0800
            String dateString = (String) sourceMap.get("createTime");
            String hours = dateString.substring(HOURSTART, HOUREND);
            if (!recordMap.containsKey(hours)) {
                Map<String, Object> map = new HashMap<>();
                recordMap.put(hours, sourceMap);
                map.put(hours, sourceMap);
                mapList.add(map);
            }
        }
        return mapList;
    }

    /***
     *
     * @param requestModel
     * @param type 0:今日，1 本周 2 本月 3 本年 （设备）   -- 4 昨天 5 前天 6 今天（拍照）
     */
    public IPage<Map> getHistoricDataPageFromEsDataV(RequestModel<DeviceAttributeStatus> requestModel, Integer type){
        Assert.notNull(requestModel, "参数为空");
        Assert.notNull(requestModel.getPage(), "分页参数为空");
        DeviceAttributeStatus deviceAttributeStatus = requestModel.getCustomQueryParams();
        Assert.notNull(deviceAttributeStatus, "getCustomQueryParams 参数不完整");
        Assert.notNull(requestModel.getCustomQueryParams(), "参数不完整");

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        if ((StringUtils.isEmpty(deviceAttributeStatus.getQueryTimeEnd())
                || StringUtils.isEmpty(deviceAttributeStatus.getQueryTimeStart()))
                && (type == null || type == 0 || type == 6)) {
            //今日
            deviceAttributeStatus.setQueryTimeStart(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            deviceAttributeStatus.setQueryTimeEnd(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
        }else if(type == 1){
            //本周
            int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
            if(day_of_week == 0){
                day_of_week = 7;
            }
            calendar.add(Calendar.DATE, -day_of_week + 1);
            deviceAttributeStatus.setQueryTimeStart(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
            calendar.add(Calendar.DATE, 6);
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            deviceAttributeStatus.setQueryTimeEnd(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
        }else if(type == 2){
            //本月
            calendar.set(Calendar.DATE, 1);
            deviceAttributeStatus.setQueryTimeStart(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
            calendar.set(Calendar.DATE, 1);
            calendar.add(Calendar.MONTH, 1);
            calendar.add(Calendar.DATE, -1);
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            deviceAttributeStatus.setQueryTimeEnd(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
        }else if(type == 3){
            //本年
            calendar.set(Calendar.MONTH,calendar.getMinimum(Calendar.MONTH));
            calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
            deviceAttributeStatus.setQueryTimeStart(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            calendar.set(Calendar.MONTH,calendar.getActualMaximum(Calendar.MONTH));
            calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
            deviceAttributeStatus.setQueryTimeEnd(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
        }else if(type == 4) {
            //昨日
            calendar.add(Calendar.DATE,-1);
            deviceAttributeStatus.setQueryTimeStart(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            deviceAttributeStatus.setQueryTimeEnd(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
        }else if(type == 5) {
            //前天
            calendar.add(Calendar.DATE,-2);
            deviceAttributeStatus.setQueryTimeStart(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            deviceAttributeStatus.setQueryTimeEnd(DateUtil.getYYYYMMDDHHMMSSDate(calendar.getTime()));
        }

        if(type == null || type == 0 || type == 4 || type == 5 || type == 6){
            IPage<Map> resultMap=null;
            if(type != null && (type == 4 || type == 5 || type == 6)){
                resultMap=getHistoricDataFromEs(requestModel);
                getDeviceHistoryDataHandler(deviceAttributeStatus,resultMap,"capture_time");
            }else{
                resultMap=deviceAttributeStatusService.getHistoricDataFromEs(requestModel);
                //getDeviceHistoryDataHandler(deviceAttributeStatus,resultMap,"createTime");
            }
            return resultMap;
        }
        IPage<Map> resultMap=deviceAttributeStatusService.getHistoricDataFromEs(requestModel);
        return resultMap;
    }

    private static void getDeviceHistoryDataHandler(DeviceAttributeStatus deviceAttributeStatus,IPage<Map> resultMap,String time){
        Assert.notNull(deviceAttributeStatus.getNecessaryFieldList(), "necessaryFieldList 参数不完整");
        List<Map> listMap=resultMap.getRecords();
        AtomicInteger i= new AtomicInteger();
        listMap = listMap.stream().map(m -> {
            i.getAndIncrement();
            m.put(time, DateUtil.format(DateUtil.getDateFromYYYYMMDDHHmmss(String.valueOf(m.get(time))),DateUtil.DATE_TIME_FORMAT_HOUR));
            m.put("autoId",i.intValue());
            return m;
        }).collect(Collectors.groupingBy(
                (Map m) -> m.get(time),
                Collectors.maxBy(Comparator.comparing(OpenApiDataVService::sort2AutoId).reversed())
        )).values().stream().map(map -> map.get())
                .sorted(Comparator.comparing(OpenApiDataVService::sort2AutoId).reversed()).collect(Collectors.toList());
        Map<String,Map> repairDate=listMap.stream().collect(Collectors.toMap((Map m)->String.valueOf(m.get(time)),m->m,(key1,key2)->key2));
        String date=DateUtil.getCurrentDateStr(DateUtil.DATE_TIME_FORMAT_HOUR);
        //如果当前时间和查询时间不是同一天，则补24小时。否则只补到当前小时
        if(!DateUtil.format(new Date(),DateUtil.DATE_TIME_FORMAT_DAY).equals(DateUtil.concat(deviceAttributeStatus.getQueryTimeEnd(),DateUtil.DATE_TIME_FORMAT_DAY))){
            date=DateUtil.concat(deviceAttributeStatus.getQueryTimeEnd(),DateUtil.DATE_TIME_FORMAT_HOUR);
        }
        listMap = getHourConllect(repairDate, DateUtil.concat(deviceAttributeStatus.getQueryTimeStart(),DateUtil.DATE_TIME_FORMAT_DAY) + " 00",date,deviceAttributeStatus,time);
        resultMap.setRecords(listMap);
        resultMap.setTotal(listMap.size());
    }

    /***
     * 根据属性值排序
     * @param map
     * @return
     */
    private static Integer sort2AutoId(Map map) {
            return Integer.valueOf(String.valueOf(map.get("autoId")));
     }

    public static List<Map> getHourConllect(Map<String, Map> hourCollect, String startHour, String endHour,DeviceAttributeStatus deviceAttributeStatus,String time) {
        List<String> hourByDay = getTimeBetween(startHour, endHour, "yyyy-MM-dd HH", Calendar.HOUR_OF_DAY);
        List<Map> resultMap = new ArrayList<>();
        for (int i = 0; i < hourByDay.size(); i++) {
            String hour = hourByDay.get(i);
            Map dataMap = hourCollect.get(hour);
            if (dataMap == null) {
                dataMap=new HashMap();
                if(deviceAttributeStatus != null && deviceAttributeStatus.getNecessaryFieldList()!= null && deviceAttributeStatus.getNecessaryFieldList().size()>0)
                {
                    for (String field:deviceAttributeStatus.getNecessaryFieldList()){
                        dataMap.put(field, Double.valueOf(0));
                    }
                }

            }
            dataMap.put(time,DateUtil.getYYYYMMDDHHMMSSDate(DateUtil.parse(hour,DateUtil.DATE_TIME_FORMAT_HOUR)));
            resultMap.add(dataMap);
        }
        return resultMap;
    }
    /**
     * 根据指定格式和Calendar.HOUR_OF_DAY等获取时间区间内所有时间段
     * @param str1
     * @param str2
     * @param format    yyyy-MM-dd MM  或者 yyyy-MM
     * @param field  Calendar.HOUR_OF_DAY   Calendar.MONTH 等
     * @return
     */
    public static List<String> getTimeBetween(String str1, String str2, String format, int field){
        List<String> list = new ArrayList<>();
        SimpleDateFormat sdf = new  SimpleDateFormat(format);
        try {
            Date startdate= sdf.parse(str1);
            Date enddate = sdf.parse(str2);
            Calendar start = Calendar.getInstance();
            start.setTime(startdate);
            while (startdate.getTime()<=enddate.getTime()){
                list.add(sdf.format(startdate));
                start.add(field,1);
                startdate = start.getTime();
            }
            //去头去尾
            /*list.remove(0);
            list.remove(list.size()-1);*/
        }catch (ParseException e){
            e.printStackTrace();
        }
        return list;
    }

    public IPage<Map> getHistoricDataFromEs(RequestModel<DeviceAttributeStatus> requestModel) {
        DeviceAttributeStatus queryModel = requestModel.getCustomQueryParams();
        Page page = requestModel.getPage();
//        如果没有勾选要查询的属性，直接返回结果
        if (ObjectUtils.isEmpty(queryModel.getNecessaryFieldList())) {
            return page;
        }
        Assert.notNull(queryModel, "customQueryParams 不能为空");
        Assert.notNull(page, "page 不能为空");
        Map<String, String> likeQueryMap = new HashMap<String, String>();
        likeQueryMap.put("deviceCode", queryModel.getDeviceCode());
        SearchHits searchHits = realService.getDeviceDataListFromESByDeviceName(likeQueryMap,
                (int)page.getCurrent(), (int)page.getSize(),
                queryModel.getQueryTimeStart(), queryModel.getQueryTimeEnd(), queryModel.getNecessaryFieldList(), null);
        if (searchHits == null) {
            return page;
        }
        LOGGER.info("es查询结果到设备历史数据条数 ：" + searchHits.getTotalHits());
        SearchHit[] results = searchHits.getHits();
        List<Map<String, Object>> records = new ArrayList<>();
        for (SearchHit hit : results) {
            Object data = hit.getSourceAsMap().get("data");
            if (org.springframework.util.ObjectUtils.isEmpty(data)) {
                continue;
            }
            Map<String, Object> sourceMap1 = (Map<String, Object>)data ;
            Map<String, Object> sourceMap = hit.getSourceAsMap();
            List<String> basicInfos = Arrays.asList("deviceCode", "deviceName", "deviceTypeName", "deviceUnitCode", "createTime");
            sourceMap.forEach((key, value) -> {
                if (basicInfos.indexOf(key) != -1) {
                    sourceMap1.put(key, value);
                }
            });
            records.add(sourceMap1);
        }
        setSpecsForEsRecords(queryModel, records);
        page.setRecords(records);
        page.setTotal(searchHits.getTotalHits());
        return page;
    }
}
